<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>类似 Vue.js 的双向绑定</title>
  <!-- 使用 BootCDN 提供的 Layui CSS -->
  <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/layui/2.8.0/css/layui.min.css">
  <!-- 使用 BootCDN 提供的 jQuery -->
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
  <!-- 使用 BootCDN 提供的 Layui JS -->
  <script src="https://cdn.bootcdn.net/ajax/libs/layui/2.8.0/layui.min.js"></script>
  <style>
    .user-item {
      margin-bottom: 10px;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 5px;
    }
    .user-item input {
      margin-right: 10px;
    }
    button {
      margin-top: 10px;
    }
  </style>
</head>
<body>
  <div class="layui-container">
    <div id="app">
      <div id="userList">
        <!-- 列表项模板 -->
        <script type="text/html" id="userTemplate">
          {{# layui.each(d.users, function(index, item){ }}
            <div class="user-item">
              <input type="text" v-model="users.{{index}}.name" placeholder="Name">
              <input type="text" v-model="users.{{index}}.age" placeholder="Age">
              <button v-on:click="removeUser({{index}})">Remove</button>
            </div>
          {{# }); }}
        </script>
      </div>
      <button v-on:click="addUser" class="layui-btn">Add User</button>
    </div>
  </div>

  <script>
    layui.use(['laytpl'], function() {
      const laytpl = layui.laytpl;

      // 类似 Vue.js 的封装方法
      class MiniVue {
        constructor(options) {
          this.$data = options.data;
          this.$methods = options.methods;
          this.$el = $(options.el); // 使用 jQuery 选择器
          this._init();
        }

        // 初始化
        _init() {
          this._observe(this.$data); // 监听数据
          this._compile(); // 编译模板
        }

        // 监听数据
        _observe(data) {
          for (let key in data) {
            if (typeof data[key] === 'object' && !Array.isArray(data[key])) {
              this._observe(data[key]); // 递归监听嵌套对象
            } else {
              this._defineReactive(data, key, data[key]);
            }
          }
        }

        // 定义响应式属性
        _defineReactive(obj, key, val) {
          const self = this;
          Object.defineProperty(obj, key, {
            get() {
              return val;
            },
            set(newVal) {
              if (newVal === val) return;
              val = newVal;
              self._updateView(); // 数据变化时更新视图
            }
          });
        }

        // 编译模板
        _compile() {
          const template = $('#userTemplate').html(); // 使用 jQuery 获取模板内容
          this.$el.html(laytpl(template).render(this.$data)); // 使用 jQuery 更新视图
          this._bindEvents(); // 绑定事件
          this._bindModel(); // 绑定双向绑定
        }

        // 绑定事件
        _bindEvents() {
          const self = this;
          this.$el.find('[v-on\\:click]').each(function() {
            const methodWithArgs = $(this).attr('v-on:click');
            const methodMatch = methodWithArgs.match(/^(\w+)$$.*$$$/);
            if (methodMatch) {
              const methodName = methodMatch;
              const argsMatch = methodWithArgs.match(/$$([^)]+)$$/);
              const args = argsMatch ? argsMatch.split(',').map(arg => arg.trim()) : [];
              $(this).on('click', function() {
                self.$methods[methodName].call(self.$data, ...args);
              });
            }
          });
        }

        // 绑定双向绑定
        _bindModel() {
          const self = this;
          this.$el.find('[v-model]').each(function() {
            const key = $(this).attr('v-model');
            $(this).val(self._getValue(self.$data, key));

            // 视图变化时更新数据模型
            $(this).on('input', function() {
              self._setValue(self.$data, key, $(this).val());
            });
          });
        }

        // 获取嵌套属性值
        _getValue(obj, path) {
          return path.split('.').reduce((o, k) => o[k], obj);
        }

        // 设置嵌套属性值
        _setValue(obj, path, value) {
          const keys = path.split('.');
          const lastKey = keys.pop();
          const target = keys.reduce((o, k) => o[k], obj);
          target[lastKey] = value;
        }

        // 更新视图
        _updateView() {
          this._compile(); // 重新编译模板
        }
      }

      // 初始化 MiniVue
      const app = new MiniVue({
        el: '#app',
        data: {
          users: [
            { name: "John", age: 25 },
            { name: "Jane", age: 30 }
          ]
        },
        methods: {
          addUser() {
            this.users.push({ name: "", age: "" });
          },
          removeUser(index) {
            this.users.splice(index, 1);
          }
        }
      });
    });
  </script>
</body>
</html>